﻿Imports System.Collections.ObjectModel
Imports System.Windows.Threading
Imports System.ComponentModel
Imports System.Text.RegularExpressions
Imports System.Net
Imports System.Globalization
Imports Co9320.NamaAlert.Model
Imports Xceed.Wpf.DataGrid

Namespace ViewModel
    Public Class MainWindowViewModel
        Inherits ViewModelBase

        Private WithEvents NicoLiveService As Model.NicoLiveService

        Private _path As ApplicationPath
        Protected ReadOnly Property Path() As ApplicationPath
            Get
                Return _path
            End Get
        End Property

        Protected ReadOnly Property ConnectionString() As String
            Get
                Return String.Format("Data Source={0};", Me.Path.DatabaseFileName)
            End Get
        End Property

#Region "Tag Service"

        Private WithEvents TagService As TagService
        'Protected ReadOnly Property Tag() As TagService
        '    Get
        '        If TagService Is Nothing Then
        '            TagService = TagService.GetTagService
        '        End If
        '        Return TagService
        '    End Get
        'End Property

        Private Sub TagService_TagChanged(ByVal sender As Object, ByVal e As Model.TagsChangedEventArgs) Handles TagService.TagChanged
            Dim programs = From p In _livePrograms Where p.Station.Id = e.StationId AndAlso p.Caster = e.Caster
            If programs.Count = 0 Then
                Exit Sub
            End If

            Dim program = programs.SingleOrDefault
            'RefreshTag(program)
            'For Each t In e.Tags
            '    program.Tags.Add(New TagViewModel(t))
            'Next

        End Sub

        Private Sub RefreshTag(ByRef liveProgram As LiveProgramViewModel)
            Exit Sub
            liveProgram.Tags.Clear()

#If DEBUG Then
            If liveProgram.Caster Is Nothing Then
                Stop
            End If
#End If

            For Each t In TagService.GetTags(liveProgram.Station.Id, liveProgram.Caster)
                liveProgram.Tags.Add(New TagViewModel(t))
            Next
            For Each t In TagService.GetTags(liveProgram.Title & vbCrLf & liveProgram.Content)
                liveProgram.Tags.Add(New TagViewModel(t))
            Next
        End Sub

#End Region

#Region "New"

        Public Sub New(ByVal path As ApplicationPath)
            MyBase.New()
            'Console.WriteLine(System.Threading.Thread.CurrentThread.ManagedThreadId)

            _path = path

            StationViewModel.CachePath = _path.CacheFolder

            ' Tag Service
            TagService.Initialize(path.DatabaseFileName, "hogehoge", "adbcdjliynmldrka")
            TagService = TagService.GetTagService

            NicoLiveService = Model.NicoLiveService.GetInstance
            NicoLiveService.Scheduling = Model.CrawlScheduling.AllPages

        End Sub

#End Region

        Private WithEvents _livePrograms As New ObservableCollection(Of LiveProgramViewModel)
        Public ReadOnly Property LivePrograms() As ObservableCollection(Of LiveProgramViewModel)
            Get
                Return _livePrograms
            End Get
        End Property

        Private WithEvents _liveProgramsViewSource As DataGridCollectionViewSource
        Public ReadOnly Property LiveProgramsViewSource() As DataGridCollectionViewSource
            Get
                If _liveProgramsViewSource Is Nothing Then
                    _liveProgramsViewSource = New DataGridCollectionViewSource
                    _liveProgramsViewSource.SortDescriptions.Add(New SortDescription("Group", ListSortDirection.Ascending))
                    ''Dim b = New DataGridItemProperty("Title", "Subset", GetType(String))
                    'Dim a = New DataGridItemProperty("Subset", GetType(LiveProgramSubsetViewModel))
                    'a.SortComparer = New AddressComparer

                    '_liveProgramsViewSource.ItemProperties.Add(a)
                    _liveProgramsViewSource.Source = _livePrograms


                End If
                Return _liveProgramsViewSource
            End Get
        End Property

        'Private _selectedLiveProgram As LiveProgramViewModel
        'Public Property SelectedLiveProgram() As LiveProgramViewModel
        '    Get
        '        Return _selectedLiveProgram
        '    End Get
        '    Set(ByVal value As LiveProgramViewModel)
        '        _selectedLiveProgram = value
        '        OnPropertyChanged("SelectedLiveProgram")
        '    End Set
        'End Property

        Private WithEvents _systemMessages As New ObservableCollection(Of SystemMessageViewModel)
        Public ReadOnly Property SystemMessages() As ObservableCollection(Of SystemMessageViewModel)
            Get
                Return _systemMessages
            End Get
        End Property

        Private _uiSettings As New UISettingsViewModel
        Public ReadOnly Property UISettings() As UISettingsViewModel
            Get
                Return _uiSettings
            End Get
        End Property

#Region "NicoLiveService evnets"

        Private Sub NicoLiveService_LiveProgramEnded(ByVal sender As Object, ByVal e As Model.LiveProgramEventArgs) Handles NicoLiveService.LiveProgramClosed
            Dim programs = From p In LivePrograms Where p.Id = e.LiveProgram.Id
            If programs.Count > 0 Then
                Dim p = programs.SingleOrDefault
                If p.Station.IsAlertTarget Then
                    p.IsOnAir = False
                Else
                    LivePrograms.Remove(p)
                End If
            End If
        End Sub

        Private Sub NicoLiveService_LiveProgramStarted(ByVal sender As Object, ByVal e As Model.LiveProgramEventArgs) Handles NicoLiveService.LiveProgramStarted

            Dim programs = From p In LivePrograms Where p.Id = e.LiveProgram.Id
            If programs.Count > 0 Then
                Dim p = programs.SingleOrDefault
                Dim s = p.Station
                p = New LiveProgramViewModel(e.LiveProgram)
                p.Station = s
                p.IsOnAir = True
            Else
                Dim p = New LiveProgramViewModel(e.LiveProgram) With {.IsOnAir = True}

                'System.InvalidOperationException はハンドルされませんでした。
                '                Message = "IComparer has failed to compare the values."
                '                Source = "Xceed.Wpf.DataGrid"
                'StackTrace:
                '       場所 Xceed.Wpf.DataGrid.DataGridCollectionViewGroup.BinarySearchRawItem(RawItem value, IComparer`1 comparer)
                '       場所 Xceed.Wpf.DataGrid.DataGridCollectionView.AddRawItemInGroup(RawItem rawItem)
                '       場所 Xceed.Wpf.DataGrid.DataGridCollectionView.AddRawItemInGroup(IList`1 rawItems)
                '       場所 Xceed.Wpf.DataGrid.DataGridCollectionView.AddSourceItem(Int32 startIndex, IList items, Int32 newSourceItemCount)
                '       場所 Xceed.Wpf.DataGrid.DataGridCollectionView.ExecuteSourceItemOperation(DeferredOperation deferredOperation)
                '       場所 Xceed.Wpf.DataGrid.DataGridCollectionViewBase.ExecuteOrQueueSourceItemOperation(DeferredOperation deferredOperation)
                '       場所 Xceed.Wpf.DataGrid.DataGridCollectionViewBase.NotifyCollectionChanged_CollectionChanged(Object sender, NotifyCollectionChangedEventArgs e)
                '       場所 Xceed.Wpf.DataGrid.DataGridCollectionViewBase.System.Windows.IWeakEventListener.ReceiveWeakEvent(Type managerType, Object sender, EventArgs e)
                '       場所 System.Windows.WeakEventManager.DeliverEventToList(Object sender, EventArgs args, ListenerList list)
                '       場所 System.Windows.WeakEventManager.DeliverEvent(Object sender, EventArgs args)
                '       場所 System.Collections.Specialized.CollectionChangedEventManager.OnCollectionChanged(Object sender, NotifyCollectionChangedEventArgs args)
                '       場所 System.Collections.ObjectModel.ObservableCollection`1.OnCollectionChanged(NotifyCollectionChangedEventArgs e)
                '       場所 System.Collections.ObjectModel.ObservableCollection`1.InsertItem(Int32 index, T item)
                '       場所 System.Collections.ObjectModel.Collection`1.Add(T item)
                '       場所 Co9320.NamaAlert.ViewModel.MainWindowViewModel.NicoLiveService_LiveProgramStarted(Object sender, LiveProgramEventArgs e) 場所 C:\Users\Owner\Documents\Visual Studio 2008\Projects\namaalert\branches\ep3\LocalClient\ViewModel\MainWindowViewModel.vb:行 134
                '       場所 Co9320.NamaAlert.Model.NicoLiveService.OnLiveProgramStarted(LiveProgramEventArgs e) 場所 C:\Users\Owner\Documents\Visual Studio 2008\Projects\namaalert\branches\ep3\NicoLiveService\NicoLiveService.vb:行 27
                '       場所 Co9320.NamaAlert.Model.NicoLiveService.UpdateLivePrograms(LiveProgramsResult result) 場所 C:\Users\Owner\Documents\Visual Studio 2008\Projects\namaalert\branches\ep3\NicoLiveService\NicoLiveService.vb:行 401
                '       場所 Co9320.NamaAlert.Model.NicoLiveService.CrawlWorker_ProgressChanged(Object sender, ProgressChangedEventArgs e) 場所 C:\Users\Owner\Documents\Visual Studio 2008\Projects\namaalert\branches\ep3\NicoLiveService\NicoLiveService.vb:行 412
                '       場所 System.ComponentModel.BackgroundWorker.OnProgressChanged(ProgressChangedEventArgs e)
                '       場所 System.ComponentModel.BackgroundWorker.ProgressReporter(Object arg)
                '       場所 System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Boolean isSingleParameter)
                '       場所 System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)
                '       場所 System.Windows.Threading.Dispatcher.WrappedInvoke(Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)
                '                場所(System.Windows.Threading.DispatcherOperation.InvokeImpl())
                '       場所 System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext(Object state)
                '       場所 System.Threading.ExecutionContext.runTryCode(Object userData)
                '       場所 System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
                '       場所 System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
                '       場所 System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
                '                場所(System.Windows.Threading.DispatcherOperation.Invoke())
                '                場所(System.Windows.Threading.Dispatcher.ProcessQueue())
                '       場所 System.Windows.Threading.Dispatcher.WndProcHook(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
                '       場所 MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
                '       場所 MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
                '       場所 System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Boolean isSingleParameter)
                '       場所 System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)
                '       場所 System.Windows.Threading.Dispatcher.WrappedInvoke(Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)
                '       場所 System.Windows.Threading.Dispatcher.InvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Boolean isSingleParameter)
                '       場所 System.Windows.Threading.Dispatcher.Invoke(DispatcherPriority priority, Delegate method, Object arg)
                '       場所 MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
                '       場所 MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)
                '       場所 System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)
                '       場所 System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame)
                '                場所(System.Windows.Threading.Dispatcher.Run())
                '       場所 System.Windows.Application.RunDispatcher(Object ignore)
                '       場所 System.Windows.Application.RunInternal(Window window)
                '       場所 System.Windows.Application.Run(Window window)
                '                場所(System.Windows.Application.Run())
                '       場所 Co9320.NamaAlert.Application.Main() 場所 C:\Users\Owner\Documents\Visual Studio 2008\Projects\namaalert\branches\ep3\LocalClient\obj\Debug\Application.g.vb:行 70
                '       場所 System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
                '       場所 System.AppDomain.nExecuteAssembly(Assembly assembly, String[] args)
                '       場所 System.Runtime.Hosting.ManifestRunner.Run(Boolean checkAptModel)
                '                場所(System.Runtime.Hosting.ManifestRunner.ExecuteAsAssembly())
                '       場所 System.Runtime.Hosting.ApplicationActivator.CreateInstance(ActivationContext activationContext, String[] activationCustomData)
                '       場所 System.Runtime.Hosting.ApplicationActivator.CreateInstance(ActivationContext activationContext)
                '       場所 System.Activator.CreateInstance(ActivationContext activationContext)
                '                場所(Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssemblyDebugInZone())
                '       場所 System.Threading.ThreadHelper.ThreadStart_Context(Object state)
                '       場所 System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
                '                場所(System.Threading.ThreadHelper.ThreadStart())
                'InnerException: System.InvalidOperationException()
                '                Message = "The property name 'Station.Name' does not exist."
                '                Source = "Xceed.Wpf.DataGrid"
                'StackTrace:
                '            場所 Xceed.Wpf.DataGrid.RawItemSortComparer.Compare(RawItem xRawItem, RawItem yRawItem)
                '            場所 Xceed.Wpf.DataGrid.DataGridCollectionViewGroup.BinarySearchRawItem(RawItem value, IComparer`1 comparer)
                'InnerException:

                LivePrograms.Add(p)
                RefreshTag(p)
                
            End If

        End Sub

        Private Sub NicoLiveService_LiveProgramUpdated(ByVal sender As Object, ByVal e As Model.LiveProgramEventArgs) Handles NicoLiveService.LiveProgramUpdated
            Dim programs = From p In LivePrograms Where p.Id = e.LiveProgram.Id
            If programs.Count > 0 Then
                With programs.SingleOrDefault
                    .Subset.Title = e.LiveProgram.Title
                    .Caster = e.LiveProgram.Caster
                    .Content = e.LiveProgram.Content
                End With
            End If
        End Sub

#End Region


#Region "Search"

        Private _searchCommand As ICommand
        Public ReadOnly Property SearchCommand() As ICommand
            Get
                If _searchCommand Is Nothing Then
                    Dim action As New Action(Of Object)(AddressOf Me.TriggerSearch)
                    _searchCommand = New RelayCommand(action)
                End If
                Return _searchCommand
            End Get
        End Property

        Private _clearSearchCommand As ICommand
        Public ReadOnly Property ClearSearchCommand() As ICommand
            Get
                If _clearSearchCommand Is Nothing Then
                    Dim action As New Action(Of Object)(AddressOf Me.ClearSearch)
                    _clearSearchCommand = New RelayCommand(action)
                End If
                Return _clearSearchCommand
            End Get
        End Property

        Private _searchText As String = ""
        Public Property SearchText() As String
            Get
                Return _searchText
            End Get
            Set(ByVal value As String)
                _searchText = value
                OnPropertyChanged("SearchText")
            End Set
        End Property

        Private WithEvents SearchTimer As New DispatcherTimer

        Private Sub TriggerSearch(ByVal obj As Object)
            SearchTimer.Stop()
            SearchTimer.Interval = New TimeSpan(5000000)
            SearchTimer.Start()
        End Sub

        Private Sub ClearSearch(ByVal obj As Object)
            Me.SearchText = ""
        End Sub

        Private Shared Function Search(ByVal program As LiveProgramViewModel, ByVal text As String) As Boolean

            Dim andWords = New List(Of String)
            Dim orWords = New List(Of String)
            Dim notWords = New List(Of String)
            Dim targetList As IList(Of String) = andWords

            Dim filterText = text.ToUpperInvariant & " " '末尾にスペースを足すのは「とある」おまじない
            Dim word As String = ""

            ' トークン分解 ループ
            For Each c In filterText
                If " 　&|-".Contains(c) AndAlso word.Length > 0 Then
                    targetList.Add(word)
                    word = ""
                End If

                Select Case c
                    Case " "c, "　"c, "&"c
                        targetList = andWords
                    Case "|"c
                        targetList = orWords
                    Case "-"c
                        targetList = notWords
                    Case Else
                        word &= c
                End Select
            Next

            ' 絞り込みワードが0個ならtrue返して関数終了
            If andWords.Count = 0 AndAlso orWords.Count = 0 AndAlso notWords.Count = 0 Then
                Return True
            End If

            ' NOTキーワードが含まれているか判別
            For Each w In notWords
                If program.Title.ToUpperInvariant.Contains(w) OrElse _
                   program.Station.Name.ToUpperInvariant.Contains(w) OrElse _
                   program.Content.ToUpperInvariant.Contains(w) OrElse _
                   If(program.Caster, "").ToUpperInvariant.Contains(w) Then

                    Return False
                End If
            Next

            ' ORキーワードが含まれているか判別
            For Each w In orWords
                If program.Title.ToUpperInvariant.Contains(w) OrElse _
                   program.Station.Name.ToUpperInvariant.Contains(w) OrElse _
                   program.Content.ToUpperInvariant.Contains(w) OrElse _
                   If(program.Caster, "").ToUpperInvariant.Contains(w) Then
                    Return True
                End If
            Next

            ' ANDキーワード全て含まれているか判別
            If andWords.Count = 0 Then
                Return False
            End If

            For Each w In andWords
                If program.Title.ToUpperInvariant.Contains(w) OrElse _
                   program.Station.Name.ToUpperInvariant.Contains(w) OrElse _
                   program.Content.ToUpperInvariant.Contains(w) OrElse _
                  If(program.Caster, "").ToUpperInvariant.Contains(w) Then
                    Continue For
                Else
                    Return False
                End If
            Next

            Return True

        End Function

        Private Sub SearchTimer_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles SearchTimer.Tick
            SearchTimer.Stop()

            ' Call Filter
            Filter(Nothing)
        End Sub

#End Region

#Region "Filter"

        Private _filterCommand As ICommand
        Public ReadOnly Property FilterCommand() As ICommand
            Get
                If _filterCommand Is Nothing Then
                    _filterCommand = New RelayCommand(New Action(Of Object)(AddressOf Me.Filter))
                End If
                Return _filterCommand
            End Get
        End Property

        Private Sub Filter(ByVal obj As Object)
            If Me.LiveProgramsViewSource IsNot Nothing Then
                Me.LiveProgramsViewSource.View.Refresh()
            End If
        End Sub

        Private Sub _liveProgramsViewSource_Filter(ByVal sender As Object, ByVal e As System.Windows.Data.FilterEventArgs) Handles _liveProgramsViewSource.Filter

            If Not TypeOf e.Item Is LiveProgramViewModel Then
                e.Accepted = False
                Exit Sub
            End If

            Dim program = DirectCast(e.Item, LiveProgramViewModel)
            If program Is Nothing OrElse program Is DBNull.Value Then
                e.Accepted = False
                Exit Sub
            End If

            ' 評価フィルター
            If UISettings.FilterByStar5 AndAlso program.Station.Rating = 5 Then
                e.Accepted = False
                Exit Sub
            End If

            If UISettings.FilterByStar4 AndAlso program.Station.Rating = 4 Then
                e.Accepted = False
                Exit Sub
            End If

            If UISettings.FilterByStar3 AndAlso program.Station.Rating = 3 Then
                e.Accepted = False
                Exit Sub
            End If

            If UISettings.FilterByStar2 AndAlso program.Station.Rating = 2 Then
                e.Accepted = False
                Exit Sub
            End If

            If UISettings.FilterByStar1 AndAlso program.Station.Rating = 1 Then
                e.Accepted = False
                Exit Sub
            End If

            If UISettings.FilterByStar0 AndAlso program.Station.Rating = 0 Then
                e.Accepted = False
                Exit Sub
            End If

            ' 検索フィルター
            If SearchText = "" Then
                e.Accepted = True
                Exit Sub
            End If

            e.Accepted = Search(program, SearchText)

        End Sub

#End Region

#Region "Common Commands"

        Private _openUriCommand As ICommand
        Public ReadOnly Property OpenUriCommand() As ICommand
            Get
                If _openUriCommand Is Nothing Then
                    _openUriCommand = New RelayCommand(New Action(Of Object)(AddressOf Me.OpenUri), New Predicate(Of Object)(AddressOf HasText))
                End If
                Return _openUriCommand
            End Get
        End Property

        Private Sub OpenUri(ByVal obj As Object)
            Dim uri = DirectCast(obj, Uri)
            Manager.BrowserManager.OpenUri(uri)
        End Sub

        Private _copyUriCommand As ICommand
        Public ReadOnly Property CopyUriCommand() As ICommand
            Get
                If _copyUriCommand Is Nothing Then
                    _copyUriCommand = New RelayCommand(New Action(Of Object)(AddressOf Me.CopyUri), New Predicate(Of Object)(AddressOf HasText))
                End If
                Return _copyUriCommand
            End Get
        End Property

        Private Sub CopyUri(ByVal obj As Object)
            Dim uri = DirectCast(obj, Uri)
            Try
                Clipboard.SetText(uri.ToString)
            Catch ex As Exception

            End Try
        End Sub

        Private Function HasText(ByVal obj As Object) As Boolean
            Return obj IsNot Nothing AndAlso (TypeOf obj Is Uri OrElse TypeOf obj Is String)
        End Function

#End Region

        Private _addAlertTargetCommand As ICommand
        Public ReadOnly Property AddAlertTargetCommand() As ICommand
            Get
                If _addAlertTargetCommand Is Nothing Then
                    _addAlertTargetCommand = New RelayCommand(New Action(Of Object)(AddressOf Me.AddAlertTarget), New Predicate(Of Object)(AddressOf CanOperateAlertTarget))
                End If
                Return _addAlertTargetCommand
            End Get
        End Property

        Private Sub AddAlertTarget(ByVal obj As Object)
            DirectCast(obj, StationViewModel).IsAlertTarget = True
        End Sub

        Private _deleteAlertTargetCommand As ICommand
        Public ReadOnly Property DeleteAlertTargetCommand() As ICommand
            Get
                If _deleteAlertTargetCommand Is Nothing Then
                    _deleteAlertTargetCommand = New RelayCommand(New Action(Of Object)(AddressOf Me.DeleteAlertTarget), New Predicate(Of Object)(AddressOf CanOperateAlertTarget))
                End If
                Return _deleteAlertTargetCommand
            End Get
        End Property

        Private Sub DeleteAlertTarget(ByVal obj As Object)
            DirectCast(obj, StationViewModel).IsAlertTarget = False
        End Sub

        Private Function CanOperateAlertTarget(ByVal obj As Object) As Boolean
            Return TypeOf obj Is StationViewModel
        End Function


#Region "Application Shutdown"
        Public Event ApplicationShutdown As EventHandler(Of EventArgs)
        Protected Overridable Sub OnApplicationShutdown(ByVal e As EventArgs)
            RaiseEvent ApplicationShutdown(Me, e)
        End Sub

        Private _shutdownApplicationCommand As ICommand
        Public ReadOnly Property ShutdownApplicationCommand() As ICommand
            Get
                If _shutdownApplicationCommand Is Nothing Then
                    Dim action = New Action(Of Object)(AddressOf Me.ShutdownApplication)
                    _shutdownApplicationCommand = New RelayCommand(action)
                End If
                Return _shutdownApplicationCommand
            End Get
        End Property

        Private Sub ShutdownApplication(ByVal obj As Object)

            Dim db = New NamaAlertDatabase(ConnectionString)

            '' Debug
            'Dim str = New System.Text.StringBuilder
            'Dim sw = New System.IO.StringWriter(str)
            'db.Log = sw

            For Each p In LivePrograms

                Dim program = New LivePrograms With { _
                    .Id = 1, _
                    .Title = p.Title, _
                    .Content = p.Content, _
                    .ShortContent = p.ShortContent, _
                    .Caster = p.Caster, _
                    .VisitorCount = p.VisitorCount, _
                    .CommentCount = p.CommentCount, _
                    .Tag = p.OfficialTag, _
                    .IsMemberOnly = p.IsMemberOnly, _
                    .IsFace = p.IsFace, _
                    .StartDateTime = p.StartDateTime, _
                    .StationId = p.Station.Id, _
                    .CrawlingDateTime = p.CrawlingDateTime}

                db.LivePrograms.InsertOnSubmit(program)

 
            Next

            'Dim log = sw.ToString


            db.Dispose()
            OnApplicationShutdown(New EventArgs)
        End Sub
#End Region

#Region "Application Show"
        Public Event ApplicationShow As EventHandler(Of EventArgs)
        Protected Overridable Sub OnApplicationShow(ByVal e As EventArgs)
            RaiseEvent ApplicationShow(Me, e)
        End Sub

        Private _showApplicationCommand As ICommand
        Public ReadOnly Property ShowApplicationCommand() As ICommand
            Get
                If _showApplicationCommand Is Nothing Then
                    _showApplicationCommand = New RelayCommand(New Action(Of Object)(AddressOf Me.ShowApplication))
                End If
                Return _showApplicationCommand
            End Get
        End Property

        Private Sub ShowApplication(ByVal obj As Object)
            OnApplicationShow(New EventArgs)
        End Sub
#End Region

#Region "Show Topmost"
        Public Event RequestShowTopmost As EventHandler(Of BooleanEventArgs)
        Protected Overridable Sub OnShowTopmost(ByVal e As BooleanEventArgs)
            RaiseEvent RequestShowTopmost(Me, e)
        End Sub

        Private _showTopmostCommand As ICommand
        Public ReadOnly Property ShowTopmostCommand() As ICommand
            Get
                If _showTopmostCommand Is Nothing Then
                    _showTopmostCommand = New RelayCommand(New Action(Of Object)(AddressOf Me.ShowTopmost))
                End If
                Return _showTopmostCommand
            End Get
        End Property

        Private Sub ShowTopmost(ByVal obj As Object)
            OnShowTopmost(New BooleanEventArgs(UISettings.Topmost))
        End Sub
#End Region



    End Class


    Public Class AddressComparer
        Implements IComparer

        Public Sub New()
        End Sub

        Public Function Compare(ByVal x As Object, ByVal y As Object) As Integer Implements IComparer.Compare

            Return 0
        End Function
    End Class
End Namespace
